home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 626-637 / disk_629 / rexxrmf / rexxrmf.lzh / rexxrmf.doc < prev    next >
Text File  |  1992-03-14  |  83KB  |  2,134 lines

  1.       
  2.  
  3.                           RexxRMF.Library
  4.  
  5.                       (version 1.8  Mar. 1992)
  6.  
  7.  
  8.  
  9.  
  10.      The  RexxRMF.library is a library which gives ARexx programs the ability
  11.  
  12.      to  maintain  'indexes' of small files for the purpose of providing fast
  13.  
  14.      search/sorting and retrieval of data records.
  15.  
  16.      The RexxRMF.library consists of several 'low' level functions that are 
  17.  
  18.      used to maintain a balanced binary tree (AVL-tree) to index your
  19.  
  20.      data files.  Built on top of the AVL-tree routines are 'high' level 
  21.  
  22.      functions to provide simple Record Management Facilities.
  23.  
  24.  
  25.  
  26.      The record management functions allow for:
  27.  
  28.          Variable length keys 
  29.  
  30.          Variable length records 
  31.  
  32.          Duplicate keys
  33.  
  34.          Mulitple indexes (ie. you can use alternate keys)
  35.  
  36.          Passing of record data directly to/from ARexx variables. 
  37.  
  38.  
  39.  
  40.  
  41.      eg.
  42.     /*  an example ARexx pgm might be */
  43.  
  44.     x = addlib("RexxRMF.library",0,-30,0)          /* make lib available */
  45.     index = open_rmf("phonelist")                  /* open index file    */
  46.     myrecord = "lastname firstname phonenumber"    /* define record      */
  47.     x = writech(stdout,"Enter Name:")              /* get search key     */
  48.     parse pull name
  49.     x = read_rmf_record(index,0,myrecord,name,'K') /* read record        */
  50.     if x = 1 then
  51.        say firstname lastname phonenumber          /* print record       */
  52.     else
  53.        say name "Not Found
  54.     x = close_rmf(index,1)
  55.     exit
  56.     
  57.     In order to use the RexxRMF.library simply place it in your LIBS:
  58.     directory.
  59.  
  60.  
  61.                           RexxRMF.Library
  62.  
  63.  
  64.  
  65.      RexxRMF library builds and maintains an AVL-tree in memory to index your 
  66.      data files.  Since the entire tree is always in memory it should be 
  67.      EMPHASIZED that RexxRMF was INTENDED for SMALL files.  How small depends 
  68.      on how much memory you have.  The amount of memory used will depend greatly
  69.      on the length of the keys and how many alternate indices you build.
  70.      
  71.      RexxRMF allows you to specify up to five alternate indices.  What this 
  72.      means is that you can have multiple keys for the same file. This allows
  73.      you not only to read a file by lastname for example, but you could also
  74.      use the month in which a person was born as an alternate key index, so
  75.      that you could send the person a birthday card in time for his/her
  76.      birthday.  
  77.  
  78.      In addition to the primary and alternate indices RexxRMF internally 
  79.      maintains a "delete" index in order to locate and keep track of deleted 
  80.      records.  In all, as many as seven indices could be present in memory
  81.      at any one time for a given file.  Each node (record) will require about
  82.      76 + keylength bytes per record.  Thus 2000 records could easily consume
  83.      170K bytes.  
  84.      Your memory configuration will determine how large 'small' can be.
  85.      
  86.      Data records on the other hand are loaded into memory when read/written
  87.      and immediately get discarded afterwards.  Data records can have as 
  88.      many fields as you wish as long as the total length of the record is
  89.      less than 65K bytes and the total number of fields is less than 65K.
  90.      With the exception of header information placed at the beginning of 
  91.      each record all data records are written as null terminated ASCII text.
  92.      Thus the datafile can be viewed with a good editor, or a "filezap" type
  93.      program, the data contents should be readily apparent. 
  94.  
  95.      Since all indices are maintained in memory, all updates to them occur 
  96.      in memory.  The index file is not written to disk until the you close 
  97.      the index with the CLOSE_RMF() function, the data file is updated 
  98.      immediately.  Their exists the possiblity that if your Amiga crashes
  99.      anytime before the index is closed, then the index and data file will 
  100.      be out of sync.  It is possible to rebuild the primary index from the 
  101.      datafile itself. Included with the RexxRMF library are two utility 
  102.      programs that can be used to rebuild the primary index.
  103.  
  104.      The library functions are fairly simple to use. The functions provide 
  105.      for the common (basic) file operations of adding, changing and 
  106.      deleting records.  The RexxRMF library passes data from the datafile 
  107.      directly to variables in your ARexx program.  You tell RexxRMF which 
  108.      program variables are to receive data by passing to the RexxRMF library
  109.      functions the names of the variables.  Data record variables are read 
  110.      and written in the order you specify.  The variable names must conform 
  111.      to ARexx naming rules and stem/compound variables are not supported.
  112.  
  113.      The function descriptions and discussion below describe the details of
  114.      using each function.
  115.  
  116.  
  117.                           RexxRMF.Library
  118.  
  119.  
  120.  
  121.  
  122.  
  123.     Record Management Functions
  124.  
  125.     Eight functions are provided for managing data file records.
  126.  
  127.     1).  OPEN_RMF()
  128.     2).  WRITE_RMF_RECORD()
  129.     3).  READ_RMF_RECORD()
  130.     4).  NEXT_RMF_RECORD()
  131.     5).  UPDATE_RMF_RECORD()
  132.     6).  UPDKEY_RMF_RECORD()
  133.     7).  DELETE_RMF_RECORD()
  134.     8).  CLOSE_RMF()
  135.  
  136.  
  137.     These functions access your ARexx program variables directly, in order
  138.     to read/write the data file.  You only need to specify the record 
  139.     layout and the names of the variables within the record.
  140.  
  141.     The functions require two files (which are automatically created) to be 
  142.     present:
  143.  
  144.     1). the data file
  145.         which contains the actual data records 
  146.  
  147.     2). the index file 
  148.         which is the file that contains the tree information. 
  149.  
  150.     If you create a file using these routines then it is probably best
  151.     that you use only these routines to manage them, since it is real
  152.     easy screw to up the indices.
  153.  
  154.  
  155.   Function Usage
  156.  
  157.     To use the functions simply call them by name as you would with 
  158.     any other ARexx or library function. 
  159.  
  160.     The functions described below require that the names of the fields 
  161.     to read/write be placed in an ARexx string variable or literal,
  162.     which I will call the 'record layout string'.  A simple assignment 
  163.     statement accomplishes the creation of the record layout string.
  164.  
  165.     eg. RECORD LAYOUT STRING
  166.  
  167.        myrecordlayout = "firstname lastname phonenumber dateofbirth"
  168.  
  169.        When the functions are called, the data will be read/written 
  170.        in the order specified in the string.  The variable names used
  171.        in the string must conform to ARexx variable name rules.
  172.        ( Stem and Compound variables are not supported)
  173.  
  174.        Within the record layout string you may insert 'special' variables
  175.        which will cause additional information to be returned to your
  176.        ARexx program. (see Special Symbol Variables below)
  177.  
  178.                           RexxRMF.Library
  179.  
  180.  
  181.  
  182.  
  183.  
  184.     Record Management Function Descriptions
  185.  
  186.  
  187.     OPEN_RMF
  188.  
  189.           Opens RMF data and index files for use.
  190.  
  191.           ix = OPEN_RMF([filename] [,dup0] [,nodata])
  192.  
  193.           OPEN_RMF accepts 3 arguments all optional.
  194.           
  195.           Inputs:
  196.  
  197.             1). filename    - the name of the data file to be indexed.
  198.                               If the index file does not exists a new 
  199.                               one will be created. The index file will 
  200.                               have a suffix of '.rmfindex'.
  201.  
  202.             2). dup0        - numeric, specifies whether the primary
  203.                               index (0) can have duplicate keys.  
  204.                               This argument is optional. Note this does
  205.                               not apply to any of the alternate indices,
  206.                               alternate indices always allow duplicates.
  207.  
  208.                               Code this as either 0 or 1.
  209.                               
  210.                               0 means duplicate keys *ARE* allowed
  211.                               1 means duplicate keys are not allowed
  212.                               The default is 0, duplicates allowed.
  213.    
  214.             2). nodata      - numeric, specifies whether a data file
  215.                               should be created/maintained.
  216.  
  217.                               Code this as either 0 or 1.
  218.                               
  219.                               0 means create a data file
  220.                               1 means do NOT create a data file
  221.                               The default is 0, create a data file.
  222.                               
  223.  
  224.                           RexxRMF.Library
  225.  
  226.  
  227.     OPEN_RMF
  228.  
  229.  
  230.           eg.
  231.               ix = open_rmf(myfile)
  232.                    opens/creates both a data and index file, with duplicates
  233.                    ALLOWED. 
  234.  
  235.               ix = open_rmf(myfile,1)
  236.                    opens/creates both a data and index file, with duplicates
  237.                    NOT ALLOWED.
  238.  
  239.               The above open calls are the ways you would normally open
  240.               the files for use.  
  241.  
  242.  
  243.               The following open calls are also legal.
  244.  
  245.               ix = open_rmf()  or open_rmf("")
  246.               
  247.               ix = open_rmf("",1)  - specifies nodups
  248.  
  249.                    neither an index nor data file are created, 'ix' will
  250.                    be valid and can only be used with the 'low' level 
  251.                    functions.  The index cannot be saved since no filename
  252.                    is specified.  This form uses the AVL-tree for its sort/
  253.                    search functions, nothing can be saved.
  254.                    
  255.               ix = open_rmf(myfile,1,1)
  256.  
  257.                    open/create an index file, duplicates NOT allowed, no
  258.                    data file is opened/created. You cannot use any of the
  259.                    ..._RMF_RECORD functions. The index can be saved.
  260.               
  261.               ix = open_rmf(myfile,0,1)
  262.  
  263.                    open/create an index file, duplicates allowed, no
  264.                    data file is opened/created. You cannot use any of the
  265.                    ..._RMF_RECORD functions. The index can be saved.
  266.               
  267.                    The intent of the above two forms is to allow you the
  268.                    ability to use RexxRMF to index your data, but leaves
  269.                    the managing (reading/writing) of the data records
  270.                    themselves to you.
  271.  
  272.               ix = open_rmf(myfile,0,0) is the same as open_rmf(myfile)
  273.  
  274.               ix = open_rmf(myfile,1,0) is the same as open_rmf(myfile,1)
  275.               
  276.  
  277.  
  278.           The data or index files will only be created if they do not 
  279.           currently exists. Otherwise the existing files are used, this
  280.           allows you to verify the index if it were rebuilt using the
  281.           the utility program 'rebuildrmfindex' described below.
  282.           
  283.  
  284.           OPEN_RMF will return non-null if the call succeeds.
  285.           The returned value is an ARexx 'packed' hex string.
  286.           This value is used by the other record management functions
  287.           to access the tree and the data file.  Basically this value
  288.           points to global data needed by the other functions.
  289.           DO NOT manipulate this value in anyway.
  290.  
  291.                           RexxRMF.Library
  292.  
  293.  
  294.  
  295.  
  296.  
  297.    WRITE_RMF_RECORD
  298.  
  299.           Writes a new record to the data file.
  300.  
  301.           x = WRITE_RMF_RECORD(ix,record,key,[{ixnum1,altkey1} ... 5 ])
  302.  
  303.           WRITE_RMF_RECORD accepts up to 13 arguments, three of which are 
  304.           required arguments.  The other ten arguments are optional.
  305.           The ten optional arguments specify alternate index/key pairs to
  306.           be associated with the record.  WRITE_RMF_RECORD will always write
  307.           the primary index (index #0)
  308.  
  309.  
  310.           Inputs:
  311.  
  312.             1). ix          - global data pointer (from OPEN_RMF())
  313.  
  314.             2). record      - record layout string
  315.  
  316.             3). key         - is an ARexx variable or literal to be used as
  317.                               the key for the record.  This is the key that
  318.                               will be used to write the primary index (#0).
  319.  
  320.          4-13). num,key     - specified in pairs, these arguments identify
  321.                               alternate indices and the key to be used with 
  322.                               the index. Up to 5 alternate pairs can be used.
  323.                               The index numbers must be between 1 and 5,
  324.  
  325.                               The indices can be specified in any order, at 
  326.                               anytime. (ie. index #1 need not be used before
  327.                               index #3 or #4 are used)
  328.  
  329.                               Be aware that additional indexes are implemented
  330.                               as individual binary trees, and therefore take
  331.                               as much memory (or more depending on keylength)
  332.                               as the primary index. 
  333.  
  334.                               If index 0 is specified as an alternate, 
  335.                               it will simply be ignored.
  336.  
  337.                               If the file has been created with duplicates
  338.                               not allowed the write will fail, if the key
  339.                               currently exists in the file.
  340.  
  341.             WRITE_RMF_RECORD returns 1 if the write succeeds, otherwise 0.
  342.  
  343.                           RexxRMF.Library
  344.  
  345.  
  346.  
  347.    WRITE_RMF_RECORD
  348.  
  349.  
  350.               eg. 
  351.  
  352.               1     myrecord = "firstname lastname area phonenumber"
  353.               2     name        = "Kelly"
  354.                     lastname    = "Kelly"
  355.                     firstname   = "Ronnie"
  356.                     area        = 999
  357.                     phonenumber = "555-1212"
  358.               3     x = WRITE_RMF_RECORD(ix,myrecord,name)
  359.                  or x = WRITE_RMF_RECORD(ix,myrecord,lastname)
  360.  
  361.               stmt. 1: defines the ARexx variable names that
  362.                        will be accessed and written to the data file.
  363.  
  364.                        Also defines the layout of the data record, ie. the
  365.                        fields will be written in the order specified. This
  366.                        is important, the same order must be used to read the 
  367.                        data with READ_RMF_RECORD(). 
  368.  
  369.               stmt. 2: gives 'name' the value 'Kelly', name will then be 
  370.                        used as the key.
  371.  
  372.               stmt. 3: adds (writes) the record to the data file and updates
  373.                        the primary index with the key value taken from name.
  374.                        The primary index is always written.
  375.                        'myrecord' specifies the names of the ARexx 
  376.                        variables to use, the values of these variables 
  377.                        are obtained by the RMF library function.
  378.  
  379.  
  380.               eg.            
  381.               x = WRITE_RMF_RECORD(ix,myrecord,name,4,area)
  382.  
  383.               this statement adds the record to the file, and updates the
  384.               primary index with the key value taken from name. Also
  385.               alternate index number 4 is updated with key value taken
  386.               from the field area.  You (or the program) must now 
  387.               remember that index number 4 is indexing on area.
  388.  
  389.  
  390.               eg.            
  391.               x = WRITE_RMF_RECORD(ix,myrecord,lastname,4,area,2,firstname)
  392.  
  393.               this statement adds the record to the file, updates the
  394.               primary index with the key value taken from lastname.
  395.               Two alternate indices are used index number 4 is indexing on
  396.               area, and index number 2 in indexing on firstname.
  397.  
  398.               Note that in the two previous examples the indices were not used
  399.               in order, ie. indices 2 and 4 were specified, but 1 and 3 were 
  400.               not. If you later decide to use indices 1 or 3 then you should 
  401.               use an UPDATE_RMF_RECORD specifying indices 1 or 3 (or both).
  402.               (See UPDATE_RMF_RECORD description)
  403.  
  404.  
  405.                           RexxRMF.Library
  406.  
  407.  
  408.  
  409.    WRITE_RMF_RECORD
  410.  
  411.  
  412.  
  413.           eg.
  414.               x = WRITE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,fname)
  415.               x = WRITE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,fname,3,zip)
  416.  
  417.               The above sequence would cause two records to be written, the
  418.               first would have primary index value of 'Kelly', index 4 will 
  419.               have the value of area, and index 2 would have the value
  420.               of firstname.  
  421.               The second statement causes a second (duplicate) record to be 
  422.               written with the same index values for the primary index and
  423.               indices 2 and 4. In addition a entry would be made in index
  424.               3 for the zip code.
  425.  
  426.               If your intent is to start using index 3 for zipcodes then 
  427.               the following sequence should be used:
  428.  
  429.               WRITE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,firstname)
  430.               UPDATE_RMF_RECORD(ix,myrecord,'Kelly',4,area,2,firstname,3,zip)
  431.  
  432.               With the above sequence a second record would not be added,
  433.               but an entry will be made into index 3 for the zip code.
  434.  
  435.               To have all existing records indexed by a new index you have
  436.               to sequentially read through the entire file updating each 
  437.               record with the new index field.
  438.  
  439.                           RexxRMF.Library
  440.  
  441.  
  442.    READ_RMF_RECORD
  443.  
  444.           Read data record from file.
  445.  
  446.           x=READ_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'|'P'|'U'|'L'},[occur])
  447.  
  448.           READ_RMF_RECORD accepts six arguments, five required plus one optional.
  449.  
  450.           Inputs:
  451.  
  452.             1). ix          - global data pointer (from OPEN_RMF())          
  453.  
  454.             2). ixnum       - integer specifies which index to use
  455.                               this should be a numeric whos value is
  456.                               between 0 and 5.
  457.                               value 0     specifies the 'primary' index
  458.                               value 1 - 5 specify alternate index.
  459.  
  460.             3). record      - record layout string
  461.                               If the read is successful the ARexx variables
  462.                               named in this string will be loaded with data
  463.                               from the record that was read.
  464.  
  465.             4). key         - is an ARexx variable or literal to be used as
  466.                               the record key to read (search) for.
  467.  
  468.             5). rdtype      - this parameter must be either K, R, P, L, or U.
  469.  
  470.                               If 'K' it specifies that the 'key' argument 
  471.                               is actually a string KEY. READ_RMF_RECORD 
  472.                               will read for the record with this string key, 
  473.                               the entire key must match, including occurence.
  474.  
  475.                               If 'P' it specifies that the 'key' argument
  476.                               is actually a string KEY. READ_RMF_RECORD 
  477.                               will read for the record with this string key.
  478.                               However partial matches of the key will 
  479.                               result in success. ie. the 'key' specifies a
  480.                               sub-string anchored at the beginning of the key.
  481.  
  482.                               If 'R' it specifies that the 'key' argument
  483.                               is actually a NUMERIC record number. 
  484.                               READ_RMF_RECORD will then read the record 
  485.                               number specified by 'key', 'key' must have a 
  486.                               numeric value.  Reading by record number order
  487.                               is the same as reading in key sorted order.
  488.  
  489.                               If 'L' it specifies that the 'key' argument
  490.                               is actually a NUMERIC record number. 
  491.                               READ_RMF_RECORD will then read the record 
  492.                               number specified by 'key' in reverse order,
  493.                               'key' must have a numeric value.
  494.                               eg. if ...,'L',1) reads last record
  495.                                   if ...,'L',2) reads next to last record
  496.                                   if ...,'L',3) reads 2nd from last record
  497.                                   etc.
  498.                               ie. 'R' reads from top to bottom (ascending)
  499.                                   'L' reads from bottom to top (descending)
  500.                               If a subsequent NEXT_RMF_RECORD() call is made
  501.                               the next to the last record is read, etc.
  502.                               (see NEXT_RMF_RECORD)
  503.  
  504.                               If 'U' it specifies that the 'key' argument 
  505.                               is actually a string KEY. READ_RMF_RECORD 
  506.                               will read for the FIRST occurence of the key,
  507.                               the 'occur' argument is ignored.  Primarly
  508.                               intended for reading unique keys in the file.
  509.                               (see NEXT_RMF_RECORD)
  510.  
  511.             6). occur       - is a numeric variable or literal which 
  512.                               specifies which occurence of a key to read.
  513.                               Multiple keys with the same value are uniquely 
  514.                               identified by an occurence number. (default 1)
  515.  
  516.             READ_RMF_RECORD returns 1 if the read succeeds, otherwise 0.
  517.  
  518.                           RexxRMF.Library
  519.  
  520.  
  521.  
  522.    READ_RMF_RECORD
  523.  
  524.             eg. 
  525.  
  526.               1     myrecord = "firstname lastname phonenumber"
  527.               2     recordnum = 27
  528.               3     x = READ_RMF_RECORD(ix,0,myrecord,recordnum,'R')
  529.               4     if x = 1 then 
  530.               5        say firstname lastname phonenumber
  531.               6     else say "Record Not Found"
  532.  
  533.               stmt. 1: defines the ARexx variable names that
  534.                        will be accessed and loaded with data.
  535.  
  536.               stmt. 2: gives 'recordnum' the value 27
  537.  
  538.               stmt. 3: reads (searches the tree) the data file for record 
  539.                        number 27 (value of recordnum) and returns 1 if
  540.                        successful. If successful then the ARexx variables
  541.                        firstname, lastname, phonenumber will contain the
  542.                        contents from record 27.
  543.  
  544.             eg. 
  545.                   x = READ_RMF_RECORD(ix,0,myrecord,27,'R')
  546.                   does the same as above, read record #27.
  547.  
  548.                   x = READ_RMF_RECORD(ix,0,myrecord,27,'K')
  549.                   search for record whose key is '27', this is NOT the 
  550.                   same as the 27th record. (entire key must match)
  551.  
  552.                   x = READ_RMF_RECORD(ix,0,myrecord,"Kel",'P')
  553.                   will search for the FIRST record who's key begins with
  554.                   "Kel", partial key match. ( searches are case sensitive)
  555.  
  556.                   x = READ_RMF_RECORD(ix,0,myrecord,"Kelly",'K',3)
  557.                   will search for the THIRD occurence of a record who's 
  558.                   key is "Kelly".  Note if less than 3 exists then the 
  559.                   read will fail.
  560.  
  561.                   x = READ_RMF_RECORD(ix,0,myrecord,"Kel",'P',4)
  562.                   will search for the FOURTH occurence of a record who's 
  563.                   key begins with "Kel".
  564.                   (partial match beginning with "Kel")
  565.  
  566.                   If the index (and data file) contains the keys
  567.  
  568.                      Adams  occurence 1
  569.                      Adams  occurence 2
  570.                      Adams  occurence 3
  571.                      Keller occurence 1
  572.                      Kelly  occurence 1
  573.                      Kelly  occurence 2
  574.                      Kelvin occurence 1  <-- 4th key beginning with "Kel"
  575.                   then 
  576.                   
  577.                   x = READ_RMF_RECORD(ix,0,myrecord,"Kel",'P',4)
  578.                   
  579.                   will return the record for 'Kelvin'
  580.  
  581.                   ---------
  582.  
  583.               NOTE: if a data field is null, then RexxRMF will return
  584.                     a string value of "(null)".  This is so that it is
  585.                     immediately apparent that the field contains no data.
  586.                     If you want it to truly be null, then you will have
  587.                     to assign it a null value again.
  588.  
  589.                     ie. if phonenumber = "(null)" then phonenumber = ''
  590.  
  591.  
  592.                           RexxRMF.Library
  593.  
  594.    NEXT_RMF_RECORD
  595.  
  596.           Read the next record from the data file.
  597.  
  598.           x = NEXT_RMF_RECORD(ix,ixnum,record)
  599.  
  600.           NEXT_RMF_RECORD should only be called immediately after
  601.           a READ_RMF_RECORD has been made.  NEXT_RMF_RECORD will 
  602.           then return in sequential order the next record that
  603.           satisfies the most recent READ_RMF_RECORD call,
  604.  
  605.           NEXT_RMF_RECORD accepts three arguments, all required.
  606.  
  607.           Inputs:
  608.  
  609.             1). ix          - global data pointer (from OPEN_RMF())          
  610.  
  611.             2). ixnum       - integer specifies which index to use
  612.                               this should be a numeric whos value is
  613.                               between 0 and 5.
  614.                               value 0     specifies the 'primary' index
  615.                               value 1 - 5 specify alternates.
  616.  
  617.             3). record      - record layout string
  618.  
  619.             NEXT_RMF_RECORD returns 1 if the read succeeds, otherwise 0.
  620.  
  621.             eg. If the index (and data file) contain the keys
  622.                   
  623.          record#  1   1Adam12   occurence 1
  624.                   2   1Adam12   occurence 2
  625.                   3   1Adam12   occurence 3
  626.                   4   1Adam22   occurence 1
  627.                   5   1Adam22   occurence 2
  628.                   6   27aint11  occurence 1
  629.                   7   27aint11  occurence 2
  630.                   8   27aint11  occurence 3
  631.                   9   27aint11  occurence 4
  632.                  10   27aint11  occurence 5
  633.                  11   27aint7   occurence 1
  634.                  12   27aint7   occurence 2
  635.                  13   3MaryAdam occurence 1
  636.                  
  637.     most recent             most recent      successive calls to
  638.     READ_RMF_RECORD         READ_RMF_RECORD    NEXT_RMF_RECORD
  639.     (ix,0,myrecord, ...        returns            return
  640.                                record #           record #s
  641.  
  642.    ...,4,'R')                    4           5,6,7,8,9,10,11,12,fail
  643.  
  644.    ...,"27aint11",'K')           6           7,8,9,10,fail
  645.  
  646.    ...,"27",'P')                 6           7,8,9,10,11,12,fail
  647.  
  648.    ...,"27",'P',6)               11          12,fail
  649.    (6th occurence of '27')
  650.  
  651.    ...,"1Adam12",'U')            1           4,6,11,13,fail
  652.    (starting with "1Adam12"
  653.    return all unique keys)
  654.     
  655.    ...,1,'L') /*reverse order*/  13          12,11,10,9,8,7,6,5,4,3,2,1,fail
  656.  
  657.    ...,3,'L')                    10          9,8,7,6,5,4,3,2,1,fail
  658.  
  659.                           RexxRMF.Library
  660.  
  661.  
  662.  
  663.  
  664.  
  665.    UPDATE_RMF_RECORD
  666.  
  667.           UPDATE_RMF_RECORD is used to update a record by record number.
  668.           The record number is the number of the record in key sorted 
  669.           order. 
  670.           
  671.           eg.  If your file contained two records with keys A and C,
  672.                then the record with key A is record number 1,
  673.                and the record with key C is record number 2.
  674.                If you then add a new record to the file with key B
  675.                then record A is record 1, record B becomes record 2
  676.                and record C becomes record 3.
  677.  
  678.           The primary key will not be updated, so if you are updating
  679.           the *PRIMARY* key of a record you should use UPDKEY_RMF_RECORD,
  680.           and not UPDATE_RMF_RECORD.  Note that alternate index keys can
  681.           be updated with UPDATE_RMF_RECORD.
  682.  
  683.           x = UPDATE_RMF_RECORD(ix,record,recnum,[{ixnum1,altkey1}...])
  684.  
  685.           UPDATE_RMF_RECORD accepts 13 arguments, 3 required, 10 optional.
  686.  
  687.           Inputs:
  688.  
  689.             1). ix          - global data pointer (from OPEN_RMF())          
  690.  
  691.             2). record      - is a string which contains the variable names.
  692.                               (ie. record layout string)
  693.  
  694.             3). recnum      - is a numeric ARexx variable or string specifing
  695.                               which record number to update.
  696.  
  697.             4-13).          - alternate index key pairs                 
  698.                               these arguments must be specified in pairs
  699.                               they specify the alternate indexes and the
  700.                               key to be used with that index.
  701.                               If not specified the alternate index retains
  702.                               its current value when the record is updated.
  703.  
  704.  
  705.             UPDATE_RMF_RECORD returns 1 if the update succeeds, otherwise 0.
  706.  
  707.                           RexxRMF.Library
  708.  
  709.  
  710.  
  711.  
  712.  
  713.    UPDATE_RMF_RECORD
  714.  
  715.  
  716.  
  717.             eg. 
  718.  
  719.               1     myrecord = "firstname lastname phonenumber"
  720.               2     recordnum = 27
  721.               3     x = READ_RMF_RECORD(ix,myrecord,recordnum,'R')
  722.               4     phonenumber = " (219) 555-5555 "
  723.               5     x = UPDATE_RMF_RECORD(ix,myrecord,recordnum)
  724.  
  725.               stmt. 1: defines the ARexx variable names that
  726.                        will be accessed and written to the data file.
  727.  
  728.               stmt. 2: gives 'recordnum' the value 27
  729.  
  730.               stmt. 3: reads the data file for record number 27 
  731.  
  732.               stmt. 5: updates record 27, If successful, a NEW record 
  733.                        will be written with the new value for 'phonenumber'.
  734.  
  735.               Note the record is read first to get the current values for 
  736.               the record. Updates are done by deleting the old record and
  737.               writing the new changed record, using the current values of
  738.               of the record layout string variables.
  739.  
  740.           You may at any time add additional fields to an existing record.
  741.           Simply include the new fields in the record layout string and 
  742.           update the record.  If you were going to add new fields to all
  743.           records, then you would probably want to use two record layout 
  744.           strings. One string in the format as the record currently exists, 
  745.           and the second string in the format of the new layout.  Then 
  746.           simply read the record with the current layout and update it with
  747.           the new layout. (Dont forget to set the values of your new fields)
  748.  
  749.                           RexxRMF.Library
  750.  
  751.  
  752.    UPDKEY_RMF_RECORD
  753.  
  754.         UPDKEY_RMF_RECORD is used to update a record by key.
  755.         The primary key does not have to change, but if you will be
  756.         changing the primary key then you MUST use UPDKEY_RMF_RECORD
  757.         else the indices will get screwed up. 
  758.  
  759.         x = UPDKEY_RMF_RECORD(ix,record,okey,occr,nkey,[{ixnum1,altkey1}...])
  760.         
  761.         UPDKEY_RMF_RECORD accepts 15 arguments, 5 required, 10 optional.
  762.         
  763.           Inputs:
  764.  
  765.           1). ix          - global data pointer (from OPEN_RMF())
  766.           
  767.           2). record      - is a string which contains the variable names
  768.                             (record layout string)
  769.                             
  770.           3). okey        - the current value of the primary key 
  771.                             (ie. index 0)
  772.                             
  773.           4). occr        - numeric, which occurence of the oldkey
  774.                             defaults to 1
  775.  
  776.           5). nkey        - the new value for the primary key (index 0)
  777.                             if not changing the key, then oldkey and
  778.                             newkey should be the same.
  779.  
  780.           6-15).          - alternate index key pairs                 
  781.                             these arguments must be specified in pairs
  782.                             they specify the alternate indexes and the
  783.                             key to be used with that index.
  784.                             If not specified the alternate index retains
  785.                             its current value when the record is updated.
  786.  
  787.           UPDKEY_RMF_RECORD returns 1 if the update succeeds, otherwise 0.
  788.             
  789.             eg. 
  790.             
  791.               1     old = 'kelly'
  792.               2     occur = 1
  793.               3     new = 'KELLY'  (keys are case-sensitive)
  794.               4     x = UPDKEY_RMF_RECORD(ix,myrec,old,occur,new)
  795.               
  796.                     Updates the primary index (0), replacing the first
  797.                     occurence of 'kelly' with 'KELLY'.
  798.               or 
  799.               4     x = UPDKEY_RMF_RECORD(ix,myrec,old,occur,old)
  800.                     old key value is retained
  801.               or 
  802.               4     x = UPDKEY_RMF_RECORD(ix,myrec,old,occur,new,1,area,4,zip)
  803.               
  804.                     Updates the primary index, as well as index 1 & 4.
  805.                     
  806.                     If indices 2,3,5 are also being used, they will retain
  807.                     their current values, since the update did not specify
  808.                     new ones.
  809.  
  810.                           RexxRMF.Library
  811.  
  812.  
  813.  
  814.    DELETE_RMF_RECORD
  815.  
  816.           DELETE_RMF_RECORD deletes records from the data file and index.
  817.  
  818.           x = DELETE_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'|'L'},[occur])
  819.  
  820.           DELETE_RMF_RECORD accepts 6 arguments, 5 required, 1 optional.
  821.  
  822.           Inputs:
  823.  
  824.             1). ix          - global data pointer (from OPEN_RMF())
  825.  
  826.             2). ixnum       - integer specifies which index to use
  827.                               Note if deleting by an alternate index
  828.                               the primary node and all alternate nodes
  829.                               are deleted as well. This is a delete of
  830.                               the record and references to the record.
  831.  
  832.             3). record      - record layout string
  833.                               when a record is deleted the values from the
  834.                               deleted record are returned in the record
  835.                               layout string.
  836.  
  837.             4). key         - is an ARexx variable or string to be used as
  838.                               the key for the record.
  839.  
  840.             5). 'K' or 'R'  - parameter five must be either 'K','R', or 'L'.
  841.                 or 'L'        same as READ_RMF_RECORD.
  842.                               DELETE_RMF_RECORD(...,1,'L') del last.
  843.                               DELETE_RMF_RECORD(...,2,'L') del next to last.
  844.                               'P' and 'U' are not allowed..
  845.  
  846.             6). occur       - numeric, occurence of this key to delete
  847.                               meaningfull only if deleting by key ('K').
  848.                               (ie. their can only be one occurence of
  849.                                    a particular record number, but 
  850.                                    multiple occurences of a key)
  851.  
  852.             DELETE_RMF_RECORD returns 1 if the delete succeeds, otherwise 0.
  853.  
  854.             eg. 
  855.  
  856.               1     myrecord = "deletedfname deletedlname deletedpnumber"
  857.               2     recordnum = 27
  858.               3     x = DELETE_RMF_RECORD(ix,0,myrecord,recordnum,'R')
  859.  
  860.               stmt. 1: defines the ARexx variable names that will receieve
  861.                        the values stored in the data record.
  862.  
  863.               stmt. 2: gives 'recordnum' the value 27
  864.  
  865.               stmt. 3: deletes record number 27, and updates the index. 
  866.  
  867.               If successful, the ARexx variables specified in 'myrecord'
  868.               will contain the values from the deleted record. Thus you 
  869.               know what the values were before the record was deleted and
  870.               can write it back to the file if need be. Note these variables
  871.               can be any variables you wish. (ie. you can use one record 
  872.               layout for reads/writes and another for deletes so as not to
  873.               disturb the contents of your current read/write variables)
  874.  
  875.                           RexxRMF.Library
  876.  
  877.  
  878.  
  879.  
  880.  
  881.  
  882.    CLOSE_RMF
  883.    
  884.           This function releases the memory allocated to the tree,
  885.           so it must be called when you are done processing the file.
  886.  
  887.           x = CLOSE_RMF(ix [,saveflag])
  888.  
  889.           CLOSE_RMF accepts two arguments.
  890.           
  891.             1). ix          - global data pointer (from OPEN_RMF())
  892.             
  893.             2). saveflag    - numeric, optional, use a value of 0 to specify 
  894.                               that the index SHOULD BE SAVED.
  895.                               
  896.                               use a value of 1 to specify that the index is
  897.                               NOT TO BE SAVED.
  898.                               
  899.                               default is 0, save the index
  900.  
  901.  
  902.           CLOSE_RMF returns 0 if the close succeeds, otherwise it returns a
  903.           non-zero error code.
  904.  
  905.                           RexxRMF.Library
  906.  
  907.  
  908.  
  909.    ANY_ERR
  910.    ANY_ERROR
  911.    ANY_ERRORS
  912.    
  913.           If any of the functions fail (return zero or NULL '0000 0000'x),
  914.           this function can be used to interrogate the library for the error
  915.           condition that caused the function to fail.
  916.           
  917.           x = ANY_ERR(ix)
  918.  
  919.           ANY_ERR accepts one argument.
  920.           
  921.             1). ix          - global data pointer (from OPEN_RMF())
  922.             
  923.         Values returned:      
  924.  
  925.         RMF errors
  926.         
  927.         4000 - RECORD_NOT_FOUND
  928.                READ_RMF_RECORD failed (record does not exist)
  929.  
  930.         4100 - NO_FILE_TO_SAVE_TO
  931.                Attempt to save index file which was opened without a name.
  932.  
  933.         4200 - RECORD_KEY_EXISTS
  934.                Attempt to add key to index that did not allow duplicates.
  935.  
  936.         4300 - NODE_ALLOCATION_FAILED
  937.                Only occurs when memory allocation for node fails.
  938.                (means you got less than 76 bytes of memory left !!)
  939.  
  940.         4400 - MAX_KEYLEN_EXCEEDED
  941.                Key length is greater than 512 bytes
  942.  
  943.         4401 - ERROR_KEY_HAS_NO_LENGTH
  944.                A zero length key was used.
  945.  
  946.         4600 - MAXIMUM_INDICES_USED
  947.                You should not get this error, you should get 4700 before this
  948.                one will occur.  If you do get this error it means you some 
  949.                how managed to get past the edit checks on index number and 
  950.                the AVL algorithm itself is complaining.
  951.  
  952.         4700 - INVALID_INDEX_NUMBER
  953.                Index number you specified was not valid.
  954.                Means you used an index number < 0 or > 5.
  955.  
  956.         4800 - INVALID_NODE_POINTER
  957.                You should not get this error, but if you do it means a 
  958.                pointer to a tree node was used that had a NULL value.
  959.  
  960.         4802 - INVALID_NODE_POINTER
  961.                You should not get this error, but if you do it means a 
  962.                pointer to a tree node was used that had a NULL value.
  963.  
  964.         4804 - INVALID_NODE_ODDPOINTER
  965.                You should not get this error, but if you do it means a 
  966.                pointer to a tree node was used that had a illegal odd value.
  967.  
  968.         4806 - CANNOT_LINK_PRIMENODES
  969.                You tried to add_key() into index #0, and link it to another
  970.                'primenode' at the same time.
  971.  
  972.         4900 - INVALID_RECORD_NUMBER
  973.                You used a record number with value <= 0.
  974.         
  975.         5000 - INVALID_DELETE_TYPE
  976.                Record delete type was not 'K' or 'R'.
  977.  
  978.                           RexxRMF.Library
  979.  
  980.  
  981.  
  982.         5001 - INVALID_READ_TYPE
  983.                Record read type was not 'K' or 'R' or 'P' or 'U'.
  984.  
  985.         5100 - COULD_NOT_ADD_TO_DELETE_INDEX
  986.                A record block was deleted that has no entry in the delete
  987.                index.  Simply means your file will have a delete block that
  988.                RexxRMF will know nothing about. (similar to 4300)
  989.  
  990.         5200 - TREE_NODE_DELETION_FAILURE
  991.                If this occurs, call me, means the AVL algorithm aint working.
  992.  
  993.         5300 - TREE_NODE_INSERTION_FAILURE
  994.                If this occurs, call me, means the AVL algorithm aint working.
  995.  
  996.         5600 - FILE_READ_ERROR
  997.                An I/O error occured while reading the data file
  998.         
  999.         5602 - FILE_READ_EOF
  1000.                Read past end of data file
  1001.  
  1002.         5700 - FILE_WRITE_ERROR
  1003.                An I/O error occured while writing the data file
  1004.  
  1005.         5800 - ERROR_READ_INDEX_IOERROR
  1006.                An I/O error occured while reading the index file
  1007.  
  1008.         5801 - ERROR_READ_INDEX_ZEROKEY_LEN
  1009.                While loading index file encountered key with zero length.
  1010.                (ie. the record had no keys, neither primary nor alterate)
  1011.                Loading of the index is immediately terminated, you 
  1012.                probably do not want to save the index if this occurs. 
  1013.         
  1014.         5802 - ERROR_READ_INDEX_MAXKEY_LEN
  1015.                While loading index encountered key which exceeded MAXKEYLEN.
  1016.         
  1017.         5900 - ERROR_WRITE_INDEX_IOERROR
  1018.                An I/O error occured while writing the index file
  1019.  
  1020.         Dos errors
  1021.         
  1022.                If the error number is something less than the errors above
  1023.                then it indicates a DOS error (from IoErr())
  1024.                
  1025.           103  - ERROR_NO_FREE_STORE
  1026.  
  1027.           221  - ERROR_DISK_FULL
  1028.  
  1029.           222  - ERROR_DELETE_PROTECTED
  1030.  
  1031.           223  - ERROR_WRITE_PROTECTED
  1032.  
  1033.           224  - ERROR_READ_PROTECTED
  1034.         
  1035.                (and any others that may occur, see AmigaDos manual)
  1036.  
  1037.                           RexxRMF.Library
  1038.  
  1039.  
  1040.  
  1041.    Special Symbol Variables
  1042.                
  1043.     As mentioned above special variables can be used in the record layout
  1044.     string to return information about the record just read or written.
  1045.  
  1046.     The functions recognize nine special symbols, which must immediately 
  1047.     precede a variable name within the record layout string.
  1048.     
  1049.     The special symbols are '@', '#', '&', '=', '<', '>', '-', '%' and '*'.
  1050.  
  1051.        '@'  - returns the record address of the record just 
  1052.               read/written. This is the relative byte location
  1053.               of were the record begins in the data file.
  1054.        
  1055.        '#n' - returns the occurence number of the record,
  1056.               'n' is the index number.
  1057.        
  1058.        '&n' - returns the key of the record, useful if reading by 
  1059.               position, 'n' is the index number.
  1060.               eg. If you read record number 32, this causes the
  1061.               key for record number 32 to be returned as well.
  1062.                
  1063.        '=n' - returns the record position within the index used to 
  1064.               read/write the record, 'n' is the index number.  
  1065.               This is the position of record key in sorted order.
  1066.               
  1067.        '<'  - read only field, the fieldname following the '<' will NOT
  1068.               be written to the datafile during writes/updates, but will
  1069.               be loaded with data during reads.
  1070.               
  1071.        '>'  - write only field, the fieldname following the '>' will NOT 
  1072.               be loaded with data during reads, but will be written to the
  1073.               datafile during writes/updates.
  1074.               
  1075.               The intent of '<' and '>' was to allow a single layout string
  1076.               to be used for both reading and writing.
  1077.  
  1078.        '-'  - suppresses the reading/writing of the data.
  1079.               useful when you want to skip over fields in a data
  1080.               record (or not change their current value).
  1081.               Be particularly watchful of this when doing writes, 
  1082.               since the data will NOT be written to the file.
  1083.               When doing a read the variable is NOT loaded with
  1084.               data from the file.  A field name need not follow
  1085.               the '-' when reading a record.
  1086.               eg.  reclayout = "first last - - - address" 
  1087.               will cause the three fields following 'last' in the data
  1088.               record to be skipped.
  1089.               
  1090.        '%'  - returns the number of fields in the data record.
  1091.               For reads this is the total number of fields in the record, 
  1092.               NOT the number of fields which were loaded with data.
  1093.               For writes this *IS* the number of fields that were actually
  1094.               written, NOT the number of fields in the record layout string.
  1095.               Note for reads/writes this count includes the primary key.
  1096.  
  1097.  
  1098.        '*n' - returns the actual memory address of the tree node for this
  1099.               record.  'n' is the index number.  The value is returned as 
  1100.               an ARexx hex-string.  This value can then be used with the 
  1101.               'low' level functions described below.
  1102.               
  1103.        eg.
  1104.        
  1105.        @anyname   the '@' does not take an index number
  1106.                   stores the record address in the ARexx variable
  1107.                   'anyname'
  1108.  
  1109.        #3anyname  stores the occurence of the record key within 
  1110.                   index 3 in the ARexx variable 'anyname'
  1111.        
  1112.        &1anyname  stores the record key from index 1 in the
  1113.                   ARexx variable 'anyname'
  1114.  
  1115.        =2anyname  stores the position of the record within index 2
  1116.                   in the ARexx variable 'anyname'
  1117.  
  1118.        -anyname   the '-' does not take an index number
  1119.                   skips the reading/writing of next field
  1120.                   (remember record layout is positional)
  1121.                   
  1122.        #anyname is the same as #0anyname, index 0 is the primary index
  1123.        =anyname is the same as =0anyname, etc.
  1124.        
  1125.        These special variables can be placed any where in the record
  1126.        layout string. 
  1127.        
  1128.        eg.  myrecord = " @rba firstname lastname =x0 =3x3 phonenumber"
  1129.  
  1130.              In the above record layout string three record values and 
  1131.              three special variables will be returned.  The special 
  1132.              variables are rba, x0, and x3.
  1133.  
  1134.        success = READ_RMF_RECORD(ix,3,myrecord,phone,'K')
  1135.       
  1136.        This READ_RMF_RECORD call uses index 3 to read for a data record.
  1137.       
  1138.        The above READ_RMF_RECORD will return the following values:
  1139.      
  1140.        firstname, lastname, phonenumber will be 'stuffed' with data 
  1141.        from the file.
  1142.  
  1143.        In the 'myrecord' layout string @rba, =x0, =3x3 are specified
  1144.       
  1145.          rba = physical location in the file from which the record was read
  1146.  
  1147.          x0  = relative position of the record in the primary index
  1148.                (ie. says this is the first, second, third, etc. record
  1149.                 in the primary index.)
  1150.  
  1151.          x3  = relative position of the record in alternate index 3
  1152.      
  1153.          eg.  if the file contained the following three records
  1154.  
  1155.                       by primary, index 0           by index 3
  1156.                 rec   (indexing on lastname)    (indexing on phone)
  1157.               location
  1158.            1.   220   John Appleton 555-1232 |  555-1230  Mike Wilson
  1159.            2.   908   Ron  Kelly    555-1231 |  555-1231  Ron Kelly
  1160.            3.   1705  Mike Wilson   555-1230 |  555-1232  John Appleton
  1161.      
  1162.      
  1163.                 if the read returned the record for Mike Wilson
  1164.                 
  1165.                 then 
  1166.                     rba = 1705
  1167.                     
  1168.                     x0  = 3, ie. Mike Wilson is the third record
  1169.                              when reading by the primary index
  1170.                             
  1171.                     x3  = 1, ie. Mike Wilson is the first record
  1172.                              when reading by index 3.
  1173.  
  1174.      
  1175.       The same would be true for a WRITE_RMF_RECORD call, with the exception
  1176.       that data record values are not returned. Presumably they have the same
  1177.       values that were just written to the file.
  1178.      
  1179.        eg.  myrecord = " @rba firstname lastname =x0 =3x3 phonenumber"
  1180.  
  1181.             success = WRITE_RMF_RECORD(ix,3,myrecord,phone,'K')
  1182.      
  1183.       
  1184.       The values from firstname, lastname, phonenumber would be left 
  1185.       as they are. However, WRITE_RMF_RECORD would return to your ARexx 
  1186.       program the variables:
  1187.       
  1188.          rba = location in the file where the record was written
  1189.      
  1190.          x0  = relative position of the record in the primary index
  1191.  
  1192.          x3  = relative position of the record in alternate index 3
  1193.  
  1194.                           RexxRMF.Library
  1195.  
  1196.  
  1197.  
  1198.      Low Level Function Descriptions
  1199.  
  1200.  
  1201.      The record management functions are built on functions which directly
  1202.      manipulate the nodes of the tree.  These 'low' level functions can be
  1203.      used by your ARexx program as well.  These functions are particularly
  1204.      useful if you are simply searching for the existence of a key or record.
  1205.      
  1206.      Some of the functions return or accept pointers to the actual node
  1207.      in the tree, so be careful of when and where you use them. 
  1208.      
  1209.      Do not intermix the 'low' level ADD/UPDATE/DELETE functions with 
  1210.      the ...RMF_RECORD functions above.  The index and data file will more
  1211.      than likely get screwed up if you start adding/deleting keys behind the
  1212.      back of the ...RMF_RECORD functions.  The ADD/UPDATE/DELETE functions
  1213.      should only be used when you are managing the reading/writing of the 
  1214.      data file yourself. 
  1215.  
  1216.      The 'low' level functions do NOT perform any I/O to the data file, 
  1217.      only the in memory tree structure is accessed.  Thus when record
  1218.      content is not important, and only the existence or non-existence
  1219.      of a key value needs to be determined, it would be better to use
  1220.      these functions.
  1221.  
  1222.  
  1223.  
  1224.      'low' level function descriptions:
  1225.  
  1226.  
  1227.    --------------------------------------------------------------------------
  1228.    
  1229.       ADD_KEY
  1230.  
  1231.       add_key(ix,ixnum,keydata,rba,[primenode])
  1232.  
  1233.       Add a node into the tree with the specified key.
  1234.  
  1235.           ix          - pointer to global data
  1236.                         (returned by open_rmf)
  1237.                         
  1238.           ixnum       - numeric, which index to use
  1239.                         0 = primary index
  1240.                         1 - 5 = alternate index
  1241.                         Note if 'primenode' is specified, then 'ixnum'
  1242.                         must be 1-5. ie. you cannot link a primenode to
  1243.                         another primenode.
  1244.  
  1245.           keydata     - string, key value to be inserted in tree
  1246.  
  1247.           rba         - numeric, this is the relative block address
  1248.                         of the record data for this key.
  1249.                         eg. WRITE_RMF_RECORD() calls this function passing
  1250.                         it the rba of where the record will be written.
  1251.  
  1252.           primenode   - pointer, optional, a primary node pointer
  1253.                         (ie. a node in index #0)
  1254.                         If specified 'primenode' must be a node in index #0,
  1255.                         and 'ixnum' must be > 0. (see 'ixnum' above)
  1256.                         The newly added key will be 'linked' to this primenode.
  1257.                         Thus creating alternate key paths to the same record.
  1258.  
  1259.                         eg.1
  1260.                         Lets say you do the following:
  1261.  
  1262.           primenode ------->  node0 = ADD_KEY(ix,0,Lastname,rba0)
  1263.           its in index #0     node1 = ADD_KEY(ix,1,ZipCode,rba1)
  1264.                               node2 = ADD_KEY(ix,2,State,rba2)
  1265.                               node3 = ADD_KEY(ix,3,Employer,rba3)
  1266.                               node4 = ADD_KEY(ix,4,DeptNo,rba4)
  1267.                               node5 = ADD_KEY(ix,5,SocNum,rba5)
  1268.  
  1269.                               This results in 6 nodes being added.
  1270.                               Since RexxRMF keeps each index as a separate
  1271.                               tree, the nodes are not 'related'.  What you
  1272.                               have is six INDEPENDENT indices on a file.
  1273.                               (Which is ok, if thats what you want)
  1274.  
  1275.                               If 'SocNum' is to be an alternate key for
  1276.                               'Lastname' the above won't do it unless 
  1277.                               'rba5' = 'rba0'
  1278.  
  1279.                               However if you do the following
  1280.  
  1281.                               eg.2
  1282.           primenode ------->  node0 = ADD_KEY(ix,0,Lastname,rba0)
  1283.           its in index #0     node1 = ADD_KEY(ix,1,ZipCode,rba1,node0)
  1284.                               node2 = ADD_KEY(ix,2,State,rba2,node0)
  1285.                               node3 = ADD_KEY(ix,3,Employer,rba3,node0)
  1286.                               node4 = ADD_KEY(ix,4,DeptNo,rba4,node0)
  1287.                               node5 = ADD_KEY(ix,5,SocNum,rba5,node0)
  1288.  
  1289.                               Six nodes are still added, however the
  1290.                               nodes 1-5 will be linked to node0. The
  1291.                               'rba' values used for nodes 1-5 five will
  1292.                               be ignored and the 'rba' will be taken
  1293.                               from node0.  Thus all keys are pointing to
  1294.                               the same record, and are alternates for node0.
  1295.  
  1296.                       Note that in the first example above, if all the 'rba'
  1297.                       values are the same you accomplish building alternate
  1298.                       keys to the same record. The BIG difference is what
  1299.                       happens whens deletions are made.
  1300.                       In eg.1 deleting a key from index #5 simply deletes 
  1301.                       that key from that index (tree).
  1302.                       In eg.2 deleting a key from index #5, will delete all
  1303.                       key references (links) to the same record. Thus, the
  1304.                       primenode as well as the other alternates are deleted.
  1305.  
  1306.  
  1307.           Returns     - pointer (ARexx hex-string) to the tree node 
  1308.                         if successfully added, else NULL ('0000 0000'x)
  1309.  
  1310.  
  1311.  
  1312.    --------------------------------------------------------------------------
  1313.  
  1314.        DELETE_KEY
  1315.  
  1316.        delete_key(ix,ixnum,keydata,occur)
  1317.  
  1318.        Delete a tree node by key.
  1319.  
  1320.        If the deleted key occurs multiple times than all remaining keys will 
  1321.        have their 'occurence' number adjusted to reflect the correct number 
  1322.        of occurences.  
  1323.        
  1324.           ix          - pointer to global data
  1325.                         (returned by open_rmf)
  1326.  
  1327.           ixnum       - numeric, which index to use
  1328.  
  1329.           keydata     - string, key to delete
  1330.             
  1331.           occur       - which occurence to delete
  1332.  
  1333.           Returns     - 1 if successful, else returns zero.
  1334.  
  1335.  
  1336.    --------------------------------------------------------------------------
  1337.    
  1338.       DELETE_POS
  1339.  
  1340.       delete_pos(ix,ixnum,pos)
  1341.       
  1342.       Delete a tree node by relative position.
  1343.       
  1344.       ie. If you build a tree with ten names,delete_pos(ix,0,6) will delete
  1345.       the sixth name (in sorted order) from the primary index.
  1346.       
  1347.       If the key deleted in position 'pos' occurs multiple times than all 
  1348.       remaining keys will have their 'occurence' number adjusted to reflect
  1349.       the correct number of occurences.
  1350.  
  1351.           ix          - pointer to a IndexFile struct.
  1352.                         (returned by open_rmf)
  1353.             
  1354.           ixnum       - numeric, which index to use
  1355.  
  1356.           pos         - relative position of tree node to be deleted 
  1357.  
  1358.  
  1359.           Returns     - 1 if successful, else returns zero.
  1360.  
  1361.  
  1362.    --------------------------------------------------------------------------
  1363.  
  1364.      FIND_KEY
  1365.  
  1366.      find_key(ix,ixnum,keydata,occur)
  1367.  
  1368.      Search tree for specified key.
  1369.  
  1370.      Unlike LOCATE_KEY this function uses the entire key and the 
  1371.      occurence number must match.  READ_RMF_RECORD uses this function
  1372.      when you specify 'K'.
  1373.  
  1374.           ix          - pointer to global data
  1375.                         (returned by open_rmf)
  1376.  
  1377.           ixnum       - numeric, which index to use
  1378.  
  1379.           keydata     - pointer to keyvalue
  1380.  
  1381.           occur       - numeric, which occurence to find
  1382.  
  1383.  
  1384.           Returns     - pointer (ARexx hex-string) to the tree node
  1385.                         if successful, else returns NULL ('0000 0000'x)
  1386.  
  1387.  
  1388.    --------------------------------------------------------------------------
  1389.  
  1390.       FIND_NEXT
  1391.  
  1392.       find_next(ix,ixnum   )
  1393.  
  1394.       Find the next occurence of a key. This function should be called    
  1395.       after FIND_KEY to sequentially find all occurences.
  1396.  
  1397.       Similar to locate_next() but does not allow partial key searches.
  1398.  
  1399.           ix          - pointer to global data
  1400.                         (returned by open_rmf)
  1401.  
  1402.           ixnum       - numeric, which index to use
  1403.  
  1404.           Returns     - pointer (ARexx hex-string) to the tree node
  1405.                         if successful, else returns NULL ('0000 0000'x)
  1406.  
  1407.  
  1408.  
  1409.    --------------------------------------------------------------------------
  1410.  
  1411.  
  1412.       FIND_POS
  1413.  
  1414.       find_pos(ix,ixnum,pos)
  1415.  
  1416.       Search for tree node by relative position.  This function allows 
  1417.       searches to be done by the relative positions of the nodes, ie. in 
  1418.       sorted order, thus random/sequential searches can be made.
  1419.       READ_RMF_RECORD uses this function when you specify 'R'.      
  1420.  
  1421.           ix          - pointer to global data
  1422.                         (returned by open_rmf)
  1423.  
  1424.           ixnum       - numeric, which index to use
  1425.           
  1426.           pos         - numeric, relative position of node
  1427.                         (ie. sorted order)
  1428.                         If pos is negative the last node in the tree
  1429.                         is returned. (any negative value will do)
  1430.                         eg.
  1431.                             treenode = find_pos(ix,0,-1)
  1432.                             would return the last node in the primary index
  1433.  
  1434.                             treenode = find_pos(ix,3,-1)
  1435.                             would return the last node in index #3
  1436.  
  1437.           Returns     - pointer (ARexx hex-string) to the tree node
  1438.                         if successful, else returns NULL ('0000 0000'x)
  1439.  
  1440.  
  1441.  
  1442.  
  1443.    --------------------------------------------------------------------------
  1444.    
  1445.    
  1446.       LOCATE_KEY
  1447.  
  1448.       locate_key(ix,ixnum,keydata,occur)
  1449.       
  1450.       Search for the specified key.  This function differs from 
  1451.       FIND_KEY in that this function allows partial key searches.
  1452.       Use this function to initially set up for calls to LOCATE_NEXT(). 
  1453.       READ_RMF_RECORD uses this function when you specify 'P'.
  1454.  
  1455.           ix          - pointer to global data
  1456.                         (returned by open_rmf)
  1457.  
  1458.           ixnum       - numeric, which index to use
  1459.  
  1460.           keydata     - string, key to search for
  1461.           
  1462.           occur       - occurence number to start with
  1463.  
  1464.           Returns     - pointer (ARexx hex-string) to the tree node
  1465.                         if successful, else returns NULL ('0000 0000'x)
  1466.             
  1467.  
  1468.  
  1469.    --------------------------------------------------------------------------
  1470.  
  1471.       LOCATE_NEXT
  1472.  
  1473.       locate_next(ix,ixnum   )
  1474.  
  1475.       Find the next sequential key in the tree.  This function should
  1476.       be called after LOCATE_KEY to find the next occurence of the key.
  1477.  
  1478.       This functions differs from FIND_NEXT in that this function 
  1479.       allows partial keys to be searched.
  1480.  
  1481.  
  1482.           ix          - pointer to global data
  1483.                         (returned by open_rmf)
  1484.  
  1485.           ixnum       - numeric, which index to use
  1486.  
  1487.           Returns     - pointer (ARexx hex-string) to the tree node
  1488.                         if successful, else returns NULL ('0000 0000'x)
  1489.  
  1490.       eg.
  1491.           if the tree contains the keys 
  1492.           
  1493.               Johnson   occurence 1
  1494.               Lewis     occurence 1
  1495.               Thomas    occurence 1
  1496.               Thomas    occurence 2
  1497.               Thomas    occurence 3
  1498.               Thomphson occurence 1
  1499.               Wilson    occurence 1
  1500.  
  1501.           p = locate_key(ix,0,"Thom",1);
  1502.               will find the first occurence of Thomas
  1503.               
  1504.           p = locate_next(ix,0);
  1505.               will find the second occurence of Thomas
  1506.  
  1507.           p = locate_next(ix,0);
  1508.               will find the third occurence of Thomas
  1509.  
  1510.           p = locate_next(ix,0);
  1511.               will find the first occurence of Thomphson
  1512.  
  1513.           p = locate_next(ix,0);
  1514.               will return NULL since their no more keys beginning with
  1515.               "Thom".
  1516.  
  1517.           If the value specified for the occurence were 2 in the locate_key()
  1518.           call then the first occurence of 'Thomas' would be skipped, but 
  1519.           all others would be found, including 'Thomphson'.
  1520.  
  1521.  
  1522.    --------------------------------------------------------------------------
  1523.  
  1524.       KEY_VALUE
  1525.       
  1526.       key_value(treenode [,ixnum])
  1527.  
  1528.       Returns the value of the key for the treenode, or the value of a
  1529.       key from an alternate of the treenode.
  1530.  
  1531.  
  1532.           treenode    - pointer to a tree node, the functions
  1533.                         ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
  1534.                         LOCATE_KEY(), and LOCATE_NEXT() return pointers
  1535.                         to tree nodes.
  1536.  
  1537.           ixnum       - index number, 0-5, this parm is optional.
  1538.                         If not specified the value of key for the
  1539.                         treenode is returned.
  1540.                         If an index number is specified, 0-5, then the
  1541.                         value of the key for the specified alternate index 
  1542.                         node is returned.
  1543.  
  1544.                         eg.  
  1545.                             lets say primary index (0) indexes on lastname
  1546.                             and alternate index 2 indexes on zip code.
  1547.  
  1548.                             treenode = find_key(ix,2,"60649",1)
  1549.  
  1550.                             The above looks in alternate index 2 for the
  1551.                             first occurence of zip code 60649, a pointer
  1552.                             to the tree node is returned.
  1553.                             
  1554.                             Given the treenode returned from alternate 
  1555.                             index 2, we can get the value of the key in
  1556.                             the primary index (0) with the statement:
  1557.  
  1558.                             lname = key_value(treenode,0)
  1559.  
  1560.                             This returns the value of 'lastname' associated
  1561.                             with the treenode from alternate index 2.
  1562.  
  1563.  
  1564.                             Similarly the values of the other alternate
  1565.                             keys associated with 60649, can be obtained
  1566.                             with 
  1567.  
  1568.                             alt1key = key_value(treenode,1)
  1569.                             alt3key = key_value(treenode,3)
  1570.                             alt4key = key_value(treenode,4)
  1571.                             alt5key = key_value(treenode,5)
  1572.  
  1573.                             Thus given a treenode the value of any of its
  1574.                             keys primary or alternate can be obtained.
  1575.  
  1576.  
  1577.                             The value of the zipcode is simply the value
  1578.                             of the key for the treenode.
  1579.  
  1580.                             zip   = key_value(treenode) = 60649
  1581.                             or 
  1582.                             zip   = key_value(treenode,2) = 60649
  1583.                                     since index 2 indexes on zipcode
  1584.  
  1585.  
  1586.  
  1587.           Returns     - string, the key for the node
  1588.  
  1589.    
  1590.    --------------------------------------------------------------------------
  1591.  
  1592.  
  1593.       KEY_COUNT
  1594.       
  1595.       key_count(ix,ixnum,key,{ 'K' | 'P' })
  1596.  
  1597.       Returns a count of the number treenodes with the value 'key'.
  1598.  
  1599.           ix          - pointer to global data
  1600.                         (returned by open_rmf)
  1601.  
  1602.           ixnum       - index number, 0-5, (0=primary)
  1603.  
  1604.           key         - string, value of key to be counted
  1605.           
  1606.           type        - string, 'K' specifies that the entire key must
  1607.                         match. 'P' specifies that partial matches of key
  1608.                         be counted as well.
  1609.  
  1610.                       eg.  count = key_count(ix,3,"708",'K')
  1611.                            counts the number of keys in alternate index 3
  1612.                            with the value of "708".
  1613.  
  1614.           Returns     - numeric, number of occurences of the key
  1615.  
  1616.    
  1617.    --------------------------------------------------------------------------
  1618.  
  1619.  
  1620.       KEY_OCCUR
  1621.       
  1622.       key_occur(treenode [,ixnum])
  1623.  
  1624.       Returns the occurence number of a tree node, or the occurence number
  1625.       of an alternate.
  1626.       
  1627.  
  1628.           treenode    - pointer to a tree node, the functions
  1629.                         ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
  1630.                         LOCATE_KEY(), and LOCATE_NEXT() return pointers
  1631.                         to tree nodes.
  1632.  
  1633.           ixnum       - index number, 0-5, this parm is optional.
  1634.                         If not specified the occurence number for the
  1635.                         treenode is returned.
  1636.  
  1637.                         If an index number is specified, 0-5, then the
  1638.                         occurence number for the specified alternate index 
  1639.                         node is returned.  This similar to KEY_VALUE, given
  1640.                         a treenode the occurence number of any of its
  1641.                         alternates can be obtained.
  1642.  
  1643.  
  1644.           Returns     - numeric, the occurence number of the node
  1645.  
  1646.    
  1647.    --------------------------------------------------------------------------
  1648.  
  1649.       KEY_RBA
  1650.       
  1651.       key_rba(treenode)
  1652.  
  1653.       Returns the relative block address assigned to a tree node.
  1654.  
  1655.           treenode    - pointer to a tree node, the functions
  1656.                         ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
  1657.                         LOCATE_KEY(), and LOCATE_NEXT() return pointers
  1658.                         to tree nodes.
  1659.  
  1660.           Returns     - numeric, relative block address assigned to the node.
  1661.                         This is the value that was stored with the ADD_KEY()
  1662.                         function.
  1663.    
  1664.    --------------------------------------------------------------------------
  1665.  
  1666.       NEXT_UNIQUE
  1667.  
  1668.       next_unique(ix,ixnum)
  1669.  
  1670.       Find the next unique occurence of a key. This function should be 
  1671.       called after FIND_KEY to sequentially find all unique occurences.
  1672.       READ_RMF_RECORD uses this function when you specify 'U'.
  1673.  
  1674.  
  1675.           ix          - pointer to global data
  1676.                         (returned by open_rmf)
  1677.  
  1678.           ixnum       - numeric, which index to use
  1679.  
  1680.           Returns     - pointer (ARexx hex-string) to the tree node
  1681.                         if successful, else returns NULL ('0000 0000'x)
  1682.  
  1683.  
  1684.  
  1685.    --------------------------------------------------------------------------
  1686.  
  1687.       NODE_POS 
  1688.       
  1689.       node_pos(treenode [,ixnum])
  1690.  
  1691.       Returns the relative position (sorted order) of a node in the tree. 
  1692.  
  1693.           treenode    - pointer to a tree node, the functions
  1694.                         ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
  1695.                         LOCATE_KEY(), and LOCATE_NEXT() return pointers
  1696.                         to tree nodes.
  1697.  
  1698.           ixnum       - index number, 0-5, this parm is optional.
  1699.                         If not specified the position (in sorted order) of 
  1700.                         the treenode is returned.
  1701.  
  1702.                         If an index number is specified, 0-5, then the
  1703.                         position of the key for the alternate index node
  1704.                         is returned.   This is similar to KEY_VALUE, 
  1705.                         given a treenode the relative sorted order of
  1706.                         any of its alternate keys can be obtained.
  1707.  
  1708.  
  1709.           Returns     - numeric, relative position of the node in the tree.
  1710.                         (ie. sorted order)
  1711.  
  1712.          eg.
  1713.           if the tree contains the keys 
  1714.  
  1715.               Johnson   occurence 1
  1716.               Lewis     occurence 1
  1717.               Thomas    occurence 1
  1718.               Thomas    occurence 2
  1719.         p --> Thomas    occurence 3
  1720.               Thomphson occurence 1
  1721.               Wilson    occurence 1
  1722.  
  1723.         and  p points to the treenode containing the key 'Thomas occurence 3'
  1724.           
  1725.                then
  1726.  
  1727.                x = node_pos(p); 
  1728.  
  1729.                will return 5 for the value of x, ie. Thomas occurence 3
  1730.                is the 5th node (sorted, relative to all other keys) in
  1731.                the tree.
  1732.    
  1733.    
  1734.    --------------------------------------------------------------------------
  1735.  
  1736.       SET_DATA
  1737.       
  1738.       set_data(treenode,n,string)
  1739.  
  1740.       Set data string stored with this tree node.  This function allows
  1741.       you to store one or two data strings with the tree node.  These 
  1742.       strings can contain any information you wish to be associated with 
  1743.       the tree node.  This data does not get saved in the index file.
  1744.  
  1745.           treenode    - pointer to a tree node, the functions
  1746.                         ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
  1747.                         LOCATE_KEY(), and LOCATE_NEXT() return pointers
  1748.                         to tree nodes.
  1749.  
  1750.           n           - numeric, 
  1751.                         use 0 to specify data string 1
  1752.                         use 1 to specify data string 2
  1753.                         
  1754.           string      - string, text to be attached to the node
  1755.           
  1756.           Returns     - always returns 1
  1757.           
  1758.           eg.
  1759.                x = set_data(treenode,1,"this is a test")
  1760.                
  1761.                after the above is executed, the treenode will have the
  1762.                text "this is a test" attached as data string 2. You
  1763.                can use the GET_DATA() function to later retrieve the 
  1764.                data string attached to the node.
  1765.  
  1766.    
  1767.    --------------------------------------------------------------------------
  1768.  
  1769.       GET_DATA
  1770.       
  1771.       get_data(treenode ,n)
  1772.  
  1773.       Get data string stored with this tree node
  1774.  
  1775.           treenode    - pointer to a tree node, the functions
  1776.                         ADD_KEY(), FIND_KEY(), FIND_NEXT(), FIND_POS(),
  1777.                         LOCATE_KEY(), and LOCATE_NEXT() return pointers
  1778.                         to tree nodes.
  1779.  
  1780.           n           - numeric, use 0 to specify data string 1
  1781.                         use 1 to specify data string 2
  1782.  
  1783.           Returns     - string, the stored string data
  1784.  
  1785.  
  1786.    --------------------------------------------------------------------------
  1787.  
  1788.                           RexxRMF.Library
  1789.  
  1790.  
  1791.     RexxRMF Functions Summary
  1792.  
  1793.     number     = ANY_ERR(ix) or ANY_ERROR(ix) or ANY_ERRORS(ix)
  1794.  
  1795.     ix         = OPEN_RMF([filename] [,dup0] [,nodata])
  1796.  
  1797.     true/false = WRITE_RMF_RECORD(ix,record,key,[{ixnum1,altkey1}...5])
  1798.  
  1799.     true/false = READ_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'|'P'|'U'},[occ])
  1800.  
  1801.     true/false = NEXT_RMF_RECORD(ix,ixnum,record)
  1802.  
  1803.     true/false = UPDATE_RMF_RECORD(ix,record,recnum,[{ixnum1,altkey1}...])
  1804.  
  1805.     true/false = UPDKEY_RMF_RECORD(ix,record,okey,occr,nkey,[ixnum1,altkey1])
  1806.         
  1807.     true/false = DELETE_RMF_RECORD(ix,ixnum,record,key,{'K'|'R'},[occ])
  1808.  
  1809.     number     = CLOSE_RMF(ix,saveflag)
  1810.  
  1811.     treenode   = ADD_KEY(ix,ixnum,keydata,rba)
  1812.  
  1813.     true/false = DELETE_KEY(ix,ixnum,keydata,occ)
  1814.  
  1815.     true/false = DELETE_POS(ix,ixnum,pos)
  1816.       
  1817.     treenode   = FIND_KEY(ix,ixnum,keydata,occ)
  1818.  
  1819.     treenode   = FIND_NEXT(ix,ixnum)
  1820.  
  1821.     treenode   = FIND_POS(ix,ixnum,pos)
  1822.  
  1823.     string     = GET_DATA(treenode,n)
  1824.  
  1825.     number     = KEY_COUNT(ix,ixnum,key,{'K' | 'P'})
  1826.  
  1827.     number     = KEY_OCCUR(treenode [,ixnum])
  1828.       
  1829.     number     = KEY_RBA(treenode)
  1830.  
  1831.     string     = KEY_VALUE(treenode [,ixnum])
  1832.  
  1833.     treenode   = LOCATE_KEY(ix,ixnum,keydata,occ)
  1834.       
  1835.     treenode   = LOCATE_NEXT(ix,ixnum)
  1836.  
  1837.     treenode   = NEXT_UNIQUE(ix,ixnum)
  1838.  
  1839.     number     = NODE_POS(treenode [,ixnum])
  1840.       
  1841.     true       = SET_DATA(treenode,n,string)
  1842.  
  1843.     ----------------------------------
  1844.     true = 1, false = 0
  1845.     treenode = pointer (hex string)
  1846.  
  1847.                           RexxRMF.Library
  1848.  
  1849.  
  1850.       File Maintenance:
  1851.  
  1852.  
  1853.      The RMF functions READ_RMF_RECORD/WRITE/UPDATE etc. perform all the
  1854.      the file I/O for the data file.  When a data record is deleted its
  1855.      node entry in the tree is removed and the data block is marked as 
  1856.      deleted by storing a zero in the record length field for the record.
  1857.      The RMF functions maintain a separate tree for deleted data records.
  1858.      The RMF functions attempt to re-use deleted data record blocks as
  1859.      much as possible.
  1860.  
  1861.  
  1862.      eg. lets say you have a single record in your data file
  1863.          with a total length of 500 bytes.
  1864.  
  1865.          you update the record so that the total length is reduced to 100 
  1866.          bytes.
  1867.  
  1868.          this is whats gonna happen:
  1869.  
  1870.         1.   the recordlength of the data record is set to zero
  1871.              (you now have a file that has 500 bytes not used)
  1872.              (UPDATE_RMF_RECORD() will always do a delete of the record,
  1873.              then a write of the record)
  1874.  
  1875.         2.   an entry is made in the delete index identifing the
  1876.              location of where the deleted block occurs in the file.
  1877.              (this has to be at rba location zero, since their is only
  1878.               one record in the file)
  1879.  
  1880.         3.   the ARexx variables specified in the record string are 
  1881.              accessed and the total length computed.
  1882.              (this is gonna be 100 bytes)
  1883.  
  1884.         4.   the delete index is searched for a block whose size is
  1885.              large enough to hold the 100 bytes. This results in location
  1886.              zero (it was just deleted) being chosen. 
  1887.              (If no deleted block is large enough then the record will be 
  1888.               written at the end of the file)
  1889.  
  1890.         5.   the block at location 0 is 500 bytes, we know this from the 
  1891.              block length, we only need 100 bytes. The block at location
  1892.              zero gets split into two blocks.
  1893.  
  1894.         6.   the first block is used to hold the 100 bytes of data, a
  1895.              entry is made into the tree.
  1896.  
  1897.         7.   for the second block (balance of 400 bytes) starting at rba
  1898.              location 100, a record header is built and written to the data
  1899.              file. The record header will have a block length of 400, and
  1900.              a record length of zero.  An entry will be made into the 
  1901.              delete index that a delete block occurs at rba location 100.
  1902.  
  1903.         8.   you now have two records in the file, one of which is marked
  1904.              as deleted. 
  1905.  
  1906.  
  1907.  
  1908.         9.   Now you start writing new records to the file, so go to step
  1909.              three above.  Any new records written will attempt to re-use
  1910.              a deleted block first, splitting it as necessary.
  1911.  
  1912.              So whats the point, the point is eventually the deleted block
  1913.              will become too small to be reuseable.  Imagine what happens
  1914.              when the delete index contains several (possibly hundreds)
  1915.              of delete blocks scattered throughout the file, things can
  1916.              get pretty fragmented. Included with the lib is a small 
  1917.              utility program that will reload the data file and its index, 
  1918.              eliminating the deleted blocks from both the data file and the 
  1919.              index.  You will want to do this (reload) since the delete
  1920.              index is loaded along with the primary and any alternates, 
  1921.              if the deleted records are too small to be re-used then the 
  1922.              memory used to hold the delete index is being wasted.
  1923.  
  1924.  
  1925.  
  1926.  
  1927.         Utility Programs
  1928.         
  1929.         rebuildrmfindex - rebuilds the index file from the data file.
  1930.                           Only a index file is created, data file is left 
  1931.                           intact.
  1932.                           If you crash anytime before saving the index,
  1933.                           this program may be able to rebuild the index
  1934.                           file.
  1935.  
  1936.         reloadrmfdata   - removes deleted blocks from the data and index
  1937.                           files.  A new data file and new index file are
  1938.                           created.  For when your datafile gets really
  1939.                           fragmented.  This program is similar to the
  1940.                           rebuildrmfindex program. However reloadrmfdata
  1941.                           will cause the locations of all the data records
  1942.                           to change, specifically the data records will be
  1943.                           written to the new data file in key sorted order.
  1944.                           
  1945.         dumprmfdata     - Formatted dump of active data records.
  1946.  
  1947.         checkrmf        - display some not-so interesting statistics
  1948.                           about your index file.
  1949.                           
  1950.         Source 'C' code is included for all the above utility programs.
  1951.                           RexxRMF.Library
  1952.  
  1953.  
  1954.       Implementation Internals
  1955.  
  1956.       For those who wish to access the data file directly, since it is your
  1957.       data, the record format is given below.
  1958.  
  1959.          Data File Format:
  1960.  
  1961.          Each record in the data file has the following format
  1962.    
  1963.          record header + keydata + record data + 4 byte trailer
  1964.    
  1965.          The header is
  1966.     
  1967.            block length   = reclength + 4byte trailer
  1968.                             (ie. keydata + record data + 4)
  1969.            
  1970.            record length  = total length of all fields in
  1971.                             the record (including keys).
  1972.                             (ie. keydata + record data)
  1973.                             (deleted records have reclen = 0)
  1974.            
  1975.            field count    = number of fields in record
  1976.                                               
  1977.            keydata        = null terminated key strings, alternate keys have
  1978.                             a leading 'index' identifier byte (hex F1,F2...)
  1979.            
  1980.            record data    = individual data field strings, NULL terminated,
  1981.                             in the order specifed by the record layout string
  1982.                             when the record was written with WRITE_RMF_RECORD.
  1983.                     
  1984.            trailer        = 4 NULL bytes are written at the end of each record
  1985.                     
  1986.            (NOTE the block/record length includes the NULL terminators)
  1987.  
  1988.         eg.
  1989.  
  1990.            |header|K0,0xf1,K1,0xf2,K2,0xf3,K3,0xf4,K4,0xf5,K5|data|4nulls|
  1991.  
  1992.              K0  = primary key null terminated
  1993.              
  1994.              0xf1  this byte says the following key is for index 1
  1995.              K1  = alternate index 1 key null terminated
  1996.              
  1997.              0xf2  this byte says the following key is for index 2
  1998.              K2  = alternate index 2 key null terminated
  1999.              
  2000.              0xf3  this byte says the following key is for index 3
  2001.              K3  = alternate index 3 key null terminated
  2002.              
  2003.              0xf4  this byte says the following key is for index 4
  2004.              K4  = alternate index 4 key null terminated
  2005.              
  2006.              0xf5  this byte says the following key is for index 5
  2007.              K5  = alternate index 5 key null terminated
  2008.  
  2009.              The 0xf1-5 bytes are only present if an alternate is used.
  2010.  
  2011.              It is these key values that are used by the utility programs
  2012.              to rebuild an index.
  2013.  
  2014.         eg. data file record
  2015.            
  2016.            |record header|record keys | record data fields     |terminate|
  2017.            | 20 | 16 | 8 | Kelly,null | var1,null... var8,null | 4 nulls |
  2018.            
  2019.            block len = 20
  2020.            
  2021.            reclen    = 16
  2022.            
  2023.            #fields   = 8
  2024.            
  2025.            key       = Kelly (null terminated primary key)
  2026.            
  2027.            var1 thru var8, each var null terminated         
  2028.            
  2029.            trailer of 4 nulls
  2030.      
  2031.            The following record is marked as deleted, it has a record length
  2032.            of zero.
  2033.      
  2034.            20 | 0 | 0 | Kelly,null | var1,null... var8,null | 4 nulls |
  2035.  
  2036.  
  2037.                                RexxRMF.Library
  2038.      
  2039.      
  2040.       Index File Format:
  2041.      
  2042.      
  2043.       Index file consist of a fixed length Index Header block 
  2044.       followed by a varing number of variable length blocks.  These variable
  2045.       blocks are the keys for the data file.  (see the avl.structs.h file)
  2046.          
  2047.         
  2048.        fixeddata + [prime key,alt. keys] ... [prime key,alt. keys]
  2049.  
  2050.  
  2051.       |fixed  || fixed index data, followed by variable length keydata   ||
  2052.       |header |  recaddr1,blklen,type,status,keylength[0]-keylength[7],
  2053.                  keydatakeydatakeydatakeydatakeydatakeydatakeydatakeydata||
  2054.                     
  2055.                     
  2056.         eg.  sample index block
  2057.                     
  2058.         ||header bytes|22,10,0,A,5,0,3,2,0,0kelly708IL||
  2059.         
  2060.                  |<----  Repeats for each key in the primary index     ---->|
  2061.                  |<------------  Fixed Length DI_Info  --------->| varying  |
  2062.         ||fixed  | rba|blklen|type|status|L0|L1|L2|L3|L4|L5|L6|L7| keydata  ||
  2063.         ||header | 22 | 10   | 0  |  A   |5 |0 |3 |2 |0 |0 |0 |0 |kelly708IL||
  2064.                   
  2065.                   
  2066.               L0 is length of key for index 0 (the primary index)
  2067.               L1 is length of key for alternate index 1 
  2068.               L2 is length of key for alternate index 2, etc.
  2069.               
  2070.               A length of zero means the index not used for this record.
  2071.               
  2072.               keydata is scanned for the length specified in L0-L7
  2073.               this keydata is NOT null-terminated, so
  2074.  
  2075.                   'kelly' = key for index 0 (L0 = 5) this is the primary key
  2076.                   '708'   = key for index 2 (L2 = 3)
  2077.                   'IL'    = key for index 3 (L3 = 2)
  2078.                   
  2079.                   index 1,4,5 are not used for this record since L1,L4,L5=0
  2080.                        
  2081.       L6 - is not used.                       
  2082.       
  2083.       L7 - is used for delete index.
  2084.            if a non-zero value is in position L7 then record block is a
  2085.            deleted block.
  2086.                           RexxRMF.Library
  2087.  
  2088.  
  2089.     Limitations:
  2090.  
  2091.     Key length     - limited to 512 bytes max 
  2092.     
  2093.     Record length  - limited to 65K
  2094.     
  2095.     Alternate keys - limited to 5
  2096.     
  2097.     File size      - none, other than those imposed by the system
  2098.     
  2099.     Memory         - yes
  2100.     
  2101.     Tree size      - limited by memory
  2102.                      Entire tree is loaded into memory (sorry 'bout that).
  2103.                      Each tree node consumes approx. 76bytes + length of key.
  2104.                      Each alternate key is maintained as a separate tree.                
  2105.                      You can approximate amount of memory needed:
  2106.                      if   #recs in file         = 500
  2107.                           average keylen        = 10 bytes
  2108.                           mem = 500 x (76 + 10) = 43000
  2109.                           if alternate keys are used then
  2110.                              mem = mem x (number of indices)
  2111.  
  2112.     Stack Size     - possibly
  2113.                      Depends how big the tree gets. I suspect you will run
  2114.                      out of memory before this becomes a problem. Insertions
  2115.                      and deletions are NOT done recursively.  The freeing
  2116.                      of tree node memory is recursive.
  2117.  
  2118.     Tree Maint.    - I made the assumption that primary use would be in
  2119.                      searching and retrieving, and that few deletions
  2120.                      would occur during processing of a file. Thus it
  2121.                      is possible that the tree could become unbalanced
  2122.                      when deleting records (or nodes).  
  2123.                      This is not a problem, its just that the tree does 
  2124.                      not live up to its name (balanced binary tree) after 
  2125.                      several deletions.  If you are concerned about the tree
  2126.                      becoming de-generate then simply close the file and 
  2127.                      reopen it.
  2128.                      
  2129.                      Note re-balancing *IS* done for insertions into 
  2130.                      the tree.
  2131.  
  2132.     Future Directions:
  2133.                      Probably none.
  2134.